package cn.yza.并发.锁.ReentrantLock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/** lock、tryLock和lockInterruptibly的差別
 lock()：若lock被thread A取得，thread B会进入block状态，直到取得lock；
 tryLock()：若当下不能取得lock，thread就会放弃,返回false，也可以设置一个超时时间参数，等待多久获取不到锁就放弃；
 lockInterruptibly()：跟lock()情況一下，但是thread B可以通过interrupt中断，放弃继续等待锁

 lock 与 lockInterruptibly比较区别在于：lock 优先考虑获取锁，待获取锁成功后，才响应中断，而lockInterruptibly 优先考虑响应中断

 ReentrantLock.lockInterruptibly允许在等待时由其它线程调用等待线程的Thread.interrupt方法
 来中断等待线程的等待而直接返回，这时不用获取锁，而会抛出一个InterruptedException

 ReentrantLock.lock方法不允许Thread.interrupt中断,即使检测到Thread.isInterrupted,
 一样会继续尝试获取锁，失败则继续休眠。只是在最后获取锁成功后再把当前线程置为interrupted状态,然后再中断线程

 * @author Honglixi
 * @create 2021-11-14 13:57
 */
public class LockTest02 {
    static Lock lock1 = new ReentrantLock();
    static Lock lock2 = new ReentrantLock();
    public static void main(String[] args) throws InterruptedException {



        Thread thread = new Thread(new ThreadDemo(lock1, lock2));//该线程先获取锁1,再获取锁2
        Thread thread1 = new Thread(new ThreadDemo(lock2, lock1));//该线程先获取锁2,再获取锁1
        thread.start();
        thread1.start();
        thread.interrupt();//使第一个线程中断
    }

    static class ThreadDemo implements Runnable {
        Lock firstLock;
        Lock secondLock;
        public ThreadDemo(Lock firstLock, Lock secondLock) {
            this.firstLock = firstLock;
            this.secondLock = secondLock;
        }
        @Override
        public void run() {
            try {
//                firstLock.tryLock();
                firstLock.lockInterruptibly();
//                firstLock.lock();
                TimeUnit.MILLISECONDS.sleep(10);//更好的触发死锁
                secondLock.lockInterruptibly();
//                secondLock.lock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                firstLock.unlock();
                secondLock.unlock();
                System.out.println(Thread.currentThread().getName()+"正常结束!");
            }
        }
    }
}
